package com.ssyx.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ssyx.constant.GlobalConstant;
import com.ssyx.enums.ActivityType;
import com.ssyx.mapper.ActivityInfoMapper;
import com.ssyx.mapper.ActivityRuleMapper;
import com.ssyx.mapper.ActivitySkuMapper;
import com.ssyx.model.activity.ActivityInfo;
import com.ssyx.model.activity.ActivityRule;
import com.ssyx.model.activity.ActivitySku;
import com.ssyx.model.activity.CouponInfo;
import com.ssyx.model.order.CartInfo;
import com.ssyx.model.product.SkuInfo;
import com.ssyx.product.ProductFeignClient;
import com.ssyx.service.ActivityInfoService;
import com.ssyx.service.CouponInfoService;
import com.ssyx.vo.activity.ActivityRuleVo;
import com.ssyx.vo.order.CartInfoVo;
import com.ssyx.vo.order.OrderConfirmVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: ssyx-parent
 * @className: ActivityInfoServiceImpl
 * @description: 类
 * @data: 2024/3/15 19:52
 * @author: ihu
 * @version: 1.0
 **/

@Slf4j
@Service
public class ActivityInfoServiceImpl extends ServiceImpl<ActivityInfoMapper, ActivityInfo> implements ActivityInfoService {
	@Resource
	private ActivityInfoMapper activityInfoMapper;
	@Resource
	private ActivityRuleMapper activityRuleMapper;
	@Resource
	private ActivitySkuMapper activitySkuMapper;
	@Resource
	private CouponInfoService couponInfoService;
	@Resource
	private ProductFeignClient productFeignClient;
	
	// 优惠活动列表方法
	@Override
	public IPage<ActivityInfo> selectPage(Page<ActivityInfo> pageParam) {
		IPage<ActivityInfo> page = activityInfoMapper.selectPage(pageParam,
				Wrappers.<ActivityInfo>lambdaQuery().orderByDesc(ActivityInfo::getId));
		page.getRecords().forEach(e -> {
			if (e.getActivityType().equals(ActivityType.FULL_REDUCTION.getCode())) {
				e.setActivityTypeString(ActivityType.FULL_REDUCTION.getComment());
			} else {
				e.setActivityTypeString(ActivityType.FULL_DISCOUNT.getComment());
			}
		});
		return page;
	}
	
	// 活动规则列表方法
	@Override
	public Map<String, Object> findActivityRuleList(Long activityId) {
		Map<String, Object> result = new HashMap<>();
		// 查询活动规则列表
		List<ActivityRule> activityRuleList =
				activityRuleMapper.selectList(Wrappers.<ActivityRule>lambdaQuery().eq(ActivityRule::getActivityId,
						activityId));
		// 查询活动sku列表
		List<ActivitySku> activitySkuList =
				activitySkuMapper.selectList(Wrappers.<ActivitySku>lambdaQuery().eq(ActivitySku::getActivityId,
						activityId));
		// 查询skuId
		List<Long> skuIdList = activitySkuList.stream().map(ActivitySku::getSkuId).collect(Collectors.toList());
		// 查询sku信息
		List<SkuInfo> skuInfoList = productFeignClient.findSkuInfoList(skuIdList);
		result.put("activityRuleList", activityRuleList);
		result.put("skuInfoList", skuInfoList);
		return result;
	}
	
	// 保存活动规则
	@Transactional(rollbackFor = Exception.class)
	@Override
	public void saveActivityRule(ActivityRuleVo activityRuleVo) {
		// 删除规则和sku类别
		activityRuleMapper.delete(new QueryWrapper<ActivityRule>().eq("activity_id", activityRuleVo.getActivityId()));
		activitySkuMapper.delete(new QueryWrapper<ActivitySku>().eq("activity_id", activityRuleVo.getActivityId()));
		ActivityInfo activityInfo = getById(activityRuleVo.getActivityId());
		// 保存活动规则
		activityRuleVo.getActivityRuleList().forEach(e -> {
			e.setActivityId(activityRuleVo.getActivityId());
			e.setActivityType(activityInfo.getActivityType());
			activityRuleMapper.insert(e);
		});
		// 保存活动sku类别
		activityRuleVo.getActivitySkuList().forEach(e -> {
			e.setActivityId(activityRuleVo.getActivityId());
			activitySkuMapper.insert(e);
		});
//		List<Long> couponIdList = activityRuleVo.getCouponIdList();
	}
	
	// 根据关键字查询sku信息列表
	@Override
	public List<SkuInfo> findSkuInfoByKeyword(String keyword) {
		List<SkuInfo> skuInfoList = productFeignClient.findSkuInfoByKeyword(keyword);
		List<Long> skuIdList = skuInfoList.stream().map(SkuInfo::getId).collect(Collectors.toList());
		//已经存在的skuId，一个sku只能参加一个促销活动，所以存在的得排除
		String existSkuIdString = "," + StringUtils.join(activityInfoMapper.selectExistSkuIdList(skuIdList).toArray(),
				",") + ",";
		return skuInfoList.stream().filter(e -> !existSkuIdString.contains("," + e.getId() + ",")).collect(Collectors.toList());
	}
	
	// 查询商品获取规则数据
	@Override
	public List<ActivityRule> findActivityRule(Long skuId) {
		List<ActivityRule> activityRuleList = activityInfoMapper.selectActivityRuleList(skuId);
		if (!CollectionUtils.isEmpty(activityRuleList)) {
			activityRuleList.forEach(e -> e.setRuleDesc(this.getRuleDesc(e)));
		}
		return activityRuleList;
	}
	
	@Override
	public OrderConfirmVo findCartActivityAndCoupon(List<CartInfo> cartInfoList, Long userId) {
		// 获取购物车，每个购物项参与活动，根据活动规则分组，一个规则对应多个商品
		List<CartInfoVo> cartInfoVoList = findCartActivityList(cartInfoList);
		// 计算参与活动之后金额
		BigDecimal activityReduceAmount = cartInfoVoList.stream()
				.filter(cartInfoVo -> cartInfoVo.getActivityRule() != null)
				.map(cartInfoVo -> cartInfoVo.getActivityRule().getReduceAmount())
				.reduce(BigDecimal.ZERO, BigDecimal::add);
		
		// 获取购物车可以使用优惠卷列表
		List<CouponInfo> couponInfoList = couponInfoService.findCartCouponInfo(cartInfoList, userId);
		// 计算商品使用优惠卷之后金额，一次只能使用一张优惠卷
		BigDecimal couponReduceAmount = new BigDecimal(GlobalConstant.INTEGER_ZERO);
		if (!CollectionUtils.isEmpty(couponInfoList)) {
			couponReduceAmount = couponInfoList.stream()
					.filter(couponInfo -> couponInfo.getIsOptimal().intValue() == GlobalConstant.INTEGER_ONE)
					.map(CouponInfo::getAmount)
					.reduce(BigDecimal.ZERO, BigDecimal::add);
		}
		
		// 计算没有参与活动，没有使用优惠卷原始金额
		BigDecimal originalTotalAmount = cartInfoList.stream()
				.filter(cartInfo -> cartInfo.getIsChecked().equals(GlobalConstant.INTEGER_ONE))
				.map(cartInfo -> cartInfo.getCartPrice().multiply(new BigDecimal(cartInfo.getSkuNum())))
				.reduce(BigDecimal.ZERO, BigDecimal::add);
		// 最终金额
		BigDecimal totalAmount =
				originalTotalAmount.subtract(activityReduceAmount).subtract(couponReduceAmount);
		OrderConfirmVo orderTradeVo = new OrderConfirmVo();
		orderTradeVo.setCarInfoVoList(cartInfoVoList);
		orderTradeVo.setActivityReduceAmount(activityReduceAmount);
		orderTradeVo.setCouponInfoList(couponInfoList);
		orderTradeVo.setCouponReduceAmount(couponReduceAmount);
		orderTradeVo.setOriginalTotalAmount(originalTotalAmount);
		orderTradeVo.setTotalAmount(totalAmount);
		return orderTradeVo;
	}
	
	@Override
	public Map<Long, List<String>> findActivity(List<Long> skuIdList) {
		Map<Long, List<String>> result = new HashMap<>();
		//skuIdList遍历，得到每个skuId
		skuIdList.forEach(skuId -> {
			//根据skuId进行查询，查询sku对应活动里面规则列表
			List<ActivityRule> activityRuleList = baseMapper.findActivityRule(skuId);
			//数据封装，规则名称
			if (!CollectionUtils.isEmpty(activityRuleList)) {
				List<String> ruleList = new ArrayList<>();
				//把规则名称处理
				for (ActivityRule activityRule : activityRuleList) {
					ruleList.add(this.getRuleDesc(activityRule));
				}
				result.put(skuId, ruleList);
			}
		});
		return result;
	}
	
	@Override
	public Map<String, Object> findActivityAndCoupon(Long skuId, Long userId) {
		// 根据skuId获取sku营销活动，一个活动有多个规则
		List<ActivityRule> activityRuleList = baseMapper.findActivityRule(skuId);
		for (ActivityRule activityRule : activityRuleList) {
			String ruleDesc = this.getRuleDesc(activityRule);
			activityRule.setRuleDesc(ruleDesc);
		}
		// 根据skuId+userId查询优惠卷信息
		List<CouponInfo> couponInfoList = couponInfoService.findCouponInfoList(skuId, userId);
		// 封装到map集合，返回
		Map<String, Object> map = new HashMap<>();
		map.put("couponInfoList", couponInfoList);
		map.put("activityRuleList", activityRuleList);
		return map;
	}
	
	@Override
	public List<CartInfoVo> findCartActivityList(List<CartInfo> cartInfoList) {
		//创建最终返回集合
		List<CartInfoVo> cartInfoVoList = new ArrayList<>();
		//获取所有skuId
		List<Long> skuIdList = cartInfoList.stream().map(CartInfo::getSkuId).collect(Collectors.toList());
		//根据所有skuId列表获取参与活动
		List<ActivitySku> activitySkuList = baseMapper.selectCartActivity(skuIdList);
		//根据活动进行分组，每个活动里面有哪些skuId信息
		//map里面key是分组字段 活动id
		// value是每组里面sku列表数据，set集合
		Map<Long, Set<Long>> activityIdToSkuIdListMap = activitySkuList.stream()
				.collect(
						Collectors.groupingBy(
								ActivitySku::getActivityId,
								Collectors.mapping(ActivitySku::getSkuId, Collectors.toSet())
						)
				);
		
		//获取活动里面规则数据
		//key是活动id  value是活动里面规则列表数据
		Map<Long, List<ActivityRule>> activityIdToActivityRuleListMap
				= new HashMap<>();
		//所有活动id
		Set<Long> activityIdSet = activitySkuList.stream().map(ActivitySku::getActivityId)
				.collect(Collectors.toSet());
		if (!CollectionUtils.isEmpty(activityIdSet)) {
			List<ActivityRule> activityRuleList =
					activityRuleMapper.selectList(Wrappers.<ActivityRule>lambdaQuery().orderByDesc(ActivityRule::getConditionAmount, ActivityRule::getConditionNum).in(ActivityRule::getActivityId, activityIdSet));
			
			//封装到activityIdToActivityRuleListMap里面
			//根据活动id进行分组
			activityIdToActivityRuleListMap = activityRuleList.stream().collect(
					Collectors.groupingBy(ActivityRule::getActivityId)
			);
		}
		
		//有活动的购物项skuId
		Set<Long> activitySkuIdSet = new HashSet<>();
		if (!CollectionUtils.isEmpty(activityIdToSkuIdListMap)) {
			//遍历activityIdToSkuIdListMap集合
			for (Map.Entry<Long, Set<Long>> entry : activityIdToSkuIdListMap.entrySet()) {
				//活动id
				Long activityId = entry.getKey();
				//每个活动对应skuId列表
				Set<Long> currentActivitySkuIdSet = entry.getValue();
				//获取当前活动对应的购物项列表
				List<CartInfo> currentActivityCartInfoList = cartInfoList.stream()
						.filter(cartInfo ->
								currentActivitySkuIdSet.contains(cartInfo.getSkuId())).collect(Collectors.toList());
				//计数购物项总金额和总数量
				BigDecimal activityTotalAmount = computeTotalAmount(currentActivityCartInfoList);
				int activityTotalNum = this.computeCartNum(currentActivityCartInfoList);
				
				//计算活动对应规则
				//根据activityId获取活动对应规则
				List<ActivityRule> currentActivityRuleList =
						activityIdToActivityRuleListMap.get(activityId);
				Integer type = currentActivityRuleList.get(0).getActivityType();
				//判断活动类型：满减和打折
				ActivityRule activityRule = null;
				if (type.equals(ActivityType.FULL_REDUCTION.getCode())) {//满减"
					activityRule = computeFullReduction(activityTotalAmount, currentActivityRuleList);
				} else {//满量
					activityRule = computeFullDiscount(activityTotalNum, activityTotalAmount, currentActivityRuleList);
				}
				
				//CartInfoVo封装
				CartInfoVo cartInfoVo = new CartInfoVo();
				cartInfoVo.setActivityRule(activityRule);
				cartInfoVo.setCartInfoList(currentActivityCartInfoList);
				cartInfoVoList.add(cartInfoVo);
				
				//记录哪些购物项参与活动
				activitySkuIdSet.addAll(currentActivitySkuIdSet);
			}
		}
		
		//没有活动购物项skuId
		//获取哪些skuId没有参加活动
		skuIdList.removeAll(activitySkuIdSet);
		if (!CollectionUtils.isEmpty(skuIdList)) {
			//skuId对应购物项
			Map<Long, CartInfo> skuIdCartInfoMap = cartInfoList.stream().collect(
					Collectors.toMap(CartInfo::getSkuId, CartInfo -> CartInfo)
			);
			for (Long skuId : skuIdList) {
				CartInfoVo cartInfoVo = new CartInfoVo();
				cartInfoVo.setActivityRule(null);//没有活动
				
				List<CartInfo> cartInfos = new ArrayList<>();
				cartInfos.add(skuIdCartInfoMap.get(skuId));
				cartInfoVo.setCartInfoList(cartInfos);
				
				cartInfoVoList.add(cartInfoVo);
			}
		}
		return cartInfoVoList;
	}
	
	private String getRuleDesc(ActivityRule activityRule) {
		StringBuilder ruleDesc = new StringBuilder();
		if (activityRule.getActivityType().equals(ActivityType.FULL_REDUCTION.getCode())) {
			ruleDesc.append("满").append(activityRule.getConditionAmount()).append("元减").append(activityRule.getBenefitAmount()).append("元");
		} else {
			ruleDesc.append("满").append(activityRule.getConditionNum()).append("元打").append(activityRule.getBenefitDiscount()).append("折");
		}
		return ruleDesc.toString();
	}
	
	private BigDecimal computeTotalAmount(List<CartInfo> cartInfoList) {
		BigDecimal total = new BigDecimal(GlobalConstant.INTEGER_ZERO);
		for (CartInfo cartInfo : cartInfoList) {
			//是否选中
			if (cartInfo.getIsChecked().intValue() == GlobalConstant.INTEGER_ONE) {
				BigDecimal itemTotal = cartInfo.getCartPrice().multiply(new BigDecimal(cartInfo.getSkuNum()));
				total = total.add(itemTotal);
			}
		}
		return total;
	}
	
	private int computeCartNum(List<CartInfo> cartInfoList) {
		int total = GlobalConstant.INTEGER_ZERO;
		for (CartInfo cartInfo : cartInfoList) {
			//是否选中
			if (cartInfo.getIsChecked().intValue() == GlobalConstant.INTEGER_ONE) {
				total += cartInfo.getSkuNum();
			}
		}
		return total;
	}
	
	private ActivityRule computeFullReduction(BigDecimal totalAmount, List<ActivityRule> activityRuleList) {
		ActivityRule optimalActivityRule = null;
		//该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
		for (ActivityRule activityRule : activityRuleList) {
			//如果订单项金额大于等于满减金额，则优惠金额
			if (totalAmount.compareTo(activityRule.getConditionAmount()) >= GlobalConstant.INTEGER_ZERO) {
				//优惠后减少金额
				activityRule.setReduceAmount(activityRule.getBenefitAmount());
				optimalActivityRule = activityRule;
				break;
			}
		}
		if (optimalActivityRule == null) {
			//如果没有满足条件的取最小满足条件的一项
			optimalActivityRule = activityRuleList.get(activityRuleList.size() - GlobalConstant.INTEGER_ONE);
			optimalActivityRule.setReduceAmount(new BigDecimal(GlobalConstant.INTEGER_ZERO));
			optimalActivityRule.setSelectType(GlobalConstant.INTEGER_ONE);
			optimalActivityRule.setRuleDesc("满" + optimalActivityRule.getConditionAmount() + "元减" + optimalActivityRule.getBenefitAmount() + "元，还差" + totalAmount.subtract(optimalActivityRule.getConditionAmount()) + "元");
		} else {
			optimalActivityRule.setRuleDesc("满" + optimalActivityRule.getConditionAmount() + "元减" + optimalActivityRule.getBenefitAmount() + "元，已减" + optimalActivityRule.getReduceAmount() + "元");
			optimalActivityRule.setSelectType(GlobalConstant.INTEGER_TWO);
		}
		return optimalActivityRule;
	}
	
	private ActivityRule computeFullDiscount(Integer totalNum, BigDecimal totalAmount,
	                                         List<ActivityRule> activityRuleList) {
		ActivityRule optimalActivityRule = null;
		//该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
		for (ActivityRule activityRule : activityRuleList) {
			//如果订单项购买个数大于等于满减件数，则优化打折
			if (totalNum >= activityRule.getConditionNum()) {
				BigDecimal skuDiscountTotalAmount =
						totalAmount.multiply(activityRule.getBenefitDiscount().divide(new BigDecimal("10")));
				BigDecimal reduceAmount = totalAmount.subtract(skuDiscountTotalAmount);
				activityRule.setReduceAmount(reduceAmount);
				optimalActivityRule = activityRule;
				break;
			}
		}
		if (optimalActivityRule == null) {
			//如果没有满足条件的取最小满足条件的一项
			optimalActivityRule = activityRuleList.get(activityRuleList.size() - 1);
			optimalActivityRule.setReduceAmount(new BigDecimal(GlobalConstant.INTEGER_ZERO));
			optimalActivityRule.setSelectType(GlobalConstant.INTEGER_ONE);
			optimalActivityRule.setRuleDesc("满" + optimalActivityRule.getConditionNum() + "元打" + optimalActivityRule.getBenefitDiscount() + "折，还差" + (totalNum - optimalActivityRule.getConditionNum()) + "件");
		} else {
			optimalActivityRule.setRuleDesc("满" + optimalActivityRule.getConditionNum() + "元打" + optimalActivityRule.getBenefitDiscount() + "折，已减" + optimalActivityRule.getReduceAmount() + "元");
			optimalActivityRule.setSelectType(GlobalConstant.INTEGER_TWO);
		}
		return optimalActivityRule;
	}
}
